//CS 321 Implementation

/*
 * Temp Control Class
 * 
 * 
 * 
 * 
 * 
 */

public class TempControl
{
  //Responsible for setting and getting temperature and mode
  
  //desiredTemp, is the temperature the user wants
  float desiredTemp;
  
  //currentIndoorTemp, is the current indoor temperature
  float currentIndoorTemp;
  
  //currentOutdoorTemp, is the current outdoor temperature
  float currentOutdoorTemp;
  
  //currentIndoorHumidity, is the current indoor humidity
  float currentIndoorHumidity;
  
  //currentOutdoorHumidity, is the current outdoor humidity
  float currentOutdoorHumidity;
  
  //initialize boundary objects that class TempControl controls
  Fan myFan = new Fan();
  Heater myPriHeat = new Heater();
  Heater mySecHeat = new Heater();
  ACUnit myAC = new ACUnit();
  
  //initialize sensor boundaries
  TempSensor indoorTempSensor = new TempSensor();
  TempSensor outdoorTempSensor = new TempSensor();
  HumiditySensor indoorHumiditySensor = new HumiditySensor();
  HumiditySensor outdoorHumiditySensor = new HumiditySensor();
  
  //initialize mobile app device object
  MobileAppDevice myMobileAppDevice = new MobileAppDevice();
  
  //initialize program control
  ProgramControl progControl = new ProgramControl();
  
  //currentTime
  long currentTime;
  
  //the current mode
  String currentMode;
  
  //constructor creates the defaults temperatures
  public TempControl(float current, float desired)
  {
    Temperature myTemps=new Temperature(current,desired);
    this.currentIndoorTemp=myTemps.getCurrentTemp();
    this.desiredTemp=myTemps.getDesiredTemp();
  }
  
  //getters and setters for mode
  public String getCurrentMode()
  {
    return this.currentMode;
  }
  
  //set mode will allow the user to select a temperature and change the
  //current temp of the thermostat
  //return a String that confirms changes
  public String setMode(String mode)
  {
    if(mode.equals("fanOnly"))
    {
      activateFan();
      this.currentMode = "fanOnly";
    }
    else if(mode.equals("Off"))
    {
      //deactivate fan, pri heat, sec heat, and AC
      deactivateSecondaryHeat();
      deactivatePrimaryHeat();
      deactivateSecondaryHeat();
      deactivateAC();
      this.currentMode = "Off";
    }
    
    else if(mode.equals("AC"))
    {
      float desiredtemp = getDesiredTemp();
      regulateCooling(desiredTemp);
      this.currentMode = "AC";
    }
    
    else if(mode.equals("Heat"))
    {
      float desiredtemp = getDesiredTemp();
      regulateHeating(desiredTemp);
      this.currentMode = "Heat";
    }
    
    return ("Current mode is: " + this.currentMode);
  }
  
  //getters and setters for indoor temp
  //interacts with indoor temp sensor boundary
  public float getCurrentIndoorTemp()
  {
    return this.currentIndoorTemp;
  }
  
  public void setCurrentIndoorTemp()
  {
    this.currentIndoorTemp = indoorTempSensor.getSensorTemp();
  }
  
  //getters and setters for outdoor temp
  //interacts with outdoor temp sensor boundary
  public float getCurrentOutdoorTemp()
  {
    return this.currentOutdoorTemp;
  }
  
  public void setCurrentOutdoorTemp()
  {
    this.currentOutdoorTemp = outdoorTempSensor.getSensorTemp();
  }
  
  //getters and setters for indoor humidity
  //interacts with indoor humidity sensor boundary
  public float getCurrentIndoorHumidity()
  {
    return this.currentIndoorHumidity;
  }
  
  public void setCurrentIndoorHumidity()
  {
    this.currentIndoorHumidity = indoorHumiditySensor.getSensorHumidity();
  }
  
  //getters and setters for outdoor humidity
  //interacts with outdoor humidity sensor boundary
  public float getCurrentOutdoorHumidity()
  {
    return this.currentOutdoorHumidity;
  }
  
  public void setCurrentOutdoorHumidity()
  {
    this.currentOutdoorHumidity = outdoorHumiditySensor.getSensorHumidity();
  }
  
  //getters and setters of desired temperature
  public float getDesiredTemp()
  {
    return this.desiredTemp;
  }
  
  public void setDesiredTemp(float newDesiredTemp)
  {
    this.desiredTemp = newDesiredTemp;
  }
  
  //getters and setters for current time
  public long getCurrentTime()
  {
    return this.currentTime;
  }
  
  public void setCurrentTime()
  {
    this.currentTime = System.currentTimeMillis();
  }
  
  //on/off functionality for fan
  public boolean activateFan()
  {
    return myFan.activateFan();
  }
  
  public boolean deactivateFan()
  {
    return myFan.deactivateFan();
  }
  
  //on/off functionality for AC unit
  public boolean activateAC()
  {
    return myAC.activateAC();
  }
  
  //on/off functionality for AC unit
  public boolean deactivateAC()
  {
    return myAC.deactivateAC();
  }
  
  
  
  //on/off functionality for primary heat
  public boolean activatePrimaryHeat()
  {
    return myPriHeat.activateHeat();
  }
  
  public boolean deactivatePrimaryHeat()
  {
    return myPriHeat.deactivateHeat();
  }
  
  //on/off functionality for secondary heat
  
  public void activateSecondaryHeat()
  {
    mySecHeat.activateHeat();
  }
  
  public void deactivateSecondaryHeat()
  {
    mySecHeat.deactivateHeat();
  }
  
  //COOLING: AC turned on when desired temp less than current temp
  public boolean regulateCooling(float desiredTemp)
  {
    //precondition: heating off
    deactivatePrimaryHeat();
    deactivateSecondaryHeat();
    
    //turn fan on
    activateFan();
    float currentIndoorTemp = getCurrentIndoorTemp();
    //while desired temp less than current temp
    while(desiredTemp<this.currentIndoorTemp)
    {
      //activate AC
      activateAC();
      //update current temp from sensor
      this.currentIndoorTemp--;
      System.out.println("Current Indoor Temp: "+currentIndoorTemp);
    }
    //desired temp is greater than indoor temp
    if(desiredTemp == currentIndoorTemp)
    {
      //turn off AC
      deactivateAC();
      
    }
    
    else if(desiredTemp >currentIndoorTemp)
    {
      //turn off AC
      return false;
      
    }
    return true;
  }
  
  //HEATING: primary heating initially turned on
  //propane secondary unit turned on when desired temp not reached within 10 min OR desired temp and curr temp diff > 10 degree F
  public boolean regulateHeating(float desiredTemp)
  {
    //precondition: AC off
    deactivateAC();
    //turn fan on
    activateFan();
    //start time of heating mode
    long startHeatingTime = getCurrentTime();
    //current time
    float currentTime;
    //time elapsed
    long elapsedTime;
    //current indoor temp
    float currentIndoorTemp = getCurrentIndoorTemp();
    //temp diff between desiredTemp and current temp
    float diffTemp;
    //always initially activate primary heating
    
    while(desiredTemp > this.currentIndoorTemp)
    {
      activatePrimaryHeat();
      //update current temp
      currentIndoorTemp = getCurrentIndoorTemp();
      //update current time
      
      //changeCurrentTemp
      this.currentIndoorTemp++;
      System.out.println("Current Indoor Temp: "+this.currentIndoorTemp);
      
      currentTime = getCurrentTime();
      //update elapsed time
      elapsedTime = (long)(Math.abs(currentTime - startHeatingTime));
      //update difference in temp between desired and current
      diffTemp = (long)(Math.abs(desiredTemp-currentIndoorTemp));
      //initialize secondary heating when either elapsed time > 10 min
      //or desired temp and current time diff > 10 degree F
      
      if((elapsedTime > 10)||(diffTemp>10))
      {
        
        activateSecondaryHeat();
      }
    }
    //desired temp now less than current temp
    if(desiredTemp == currentIndoorTemp)
    {
      //deactive all heating units
      deactivatePrimaryHeat();
      deactivateSecondaryHeat();
      
    }
    
    else if(desiredTemp<currentIndoorTemp)
      return false;
    
    return true;
  }
  
  
  //monitor temp returns whether the current temp is = to the desiredtemp
  public boolean monitorTemp()
  {
    return this.desiredTemp==this.currentIndoorTemp;
  }
}